master
1---
2import { siteConfig } from '@/config';
3import BackLinks from '@components/misc/BackLinks.astro';
4import License from '@components/misc/License.astro';
5import PostInfo from '@components/misc/PostInfo.astro';
6import ImageWrapper from '@components/utils/ImageWrapper.astro';
7import Markdown from '@components/utils/Markdown.astro';
8import PostPageLayout from '@layouts/PostPageLayout.astro';
9import { getAllReferences, getPosts } from '@utils/content-utils';
10import { t } from '@utils/i18n';
11import { Icon } from 'astro-icon/components';
12import { render } from 'astro:content';
13
14export async function getStaticPaths() {
15 const posts = await getPosts();
16 return posts.map((article) => ({
17 params: { article: article.data.slug },
18 props: { article },
19 }));
20}
21
22const { article } = Astro.props;
23const { Content, headings, remarkPluginFrontmatter } = await render(article);
24const description = article.data.description || remarkPluginFrontmatter.excerpt;
25const isDraft = article.data.draft === true;
26
27const allReferences = await getAllReferences();
28const allRefByCurrent = allReferences.filter((it) => it.refBy.id === article.id);
29const allRefToCurrent = allReferences.filter((it) => it.refTo.id === article.id);
30
31const references: {
32 reference: string;
33 context: string;
34 id: string;
35}[] =
36 (
37 remarkPluginFrontmatter.references as {
38 reference: string;
39 context: string;
40 id: string;
41 }[]
42 )?.map((it) => ({
43 reference: it.reference.split('#')[0],
44 context: it.context,
45 id: it.id,
46 })) || [];
47
48const backLinks: {
49 refBy: {
50 title: string;
51 collection: 'posts' | 'spec';
52 id: string;
53 };
54 context: string;
55 offset: [number, number];
56 id: string;
57}[] = allRefToCurrent;
58---
59
60<PostPageLayout
61 title={article.data.title}
62 description={description}
63 headings={headings}
64 comment={article.data.comment}
65 lang={article.data.lang}
66 banner={typeof article.data.cover === 'string' ? article.data.cover : article.data.cover?.src}
67>
68 <Fragment slot="header-content">
69 <PostInfo
70 title={article.data.title}
71 publishedAt={article.data.published}
72 category={article.data.category}
73 tags={article.data.tags}
74 wordCount={remarkPluginFrontmatter.words}
75 readingTime={remarkPluginFrontmatter.minutes}
76 lang={article.data.lang}
77 class="mx-2 mt-4 overflow-y-scroll"
78 style={siteConfig.banner !== false ? `max-height: ${siteConfig.banner.postHeight}` : null}
79 />
80 </Fragment>
81 {
82 siteConfig.banner === false && article.data.cover && (
83 <ImageWrapper
84 src={article.data.cover}
85 class="mb-6 rounded-xl shadow"
86 alt={article.data.title}
87 />
88 )
89 }
90 <Markdown
91 bidirectional-references={{
92 references,
93 allRefByCurrent,
94 }}
95 >
96 {
97 isDraft && (
98 <blockquote class="collapse-arrow collapse" data-callout="note">
99 <input type="checkbox" checked="true" />
100 <div class="callout-title collapse-title">
101 <Icon name="mingcute:pencil-line" />
102 NOTE
103 </div>
104 <div class="collapse-content">
105 <Fragment
106 set:html={t.info.devNote({
107 configKey: 'buildConfig.showDraftsOnDev',
108 configValue: false,
109 configFilePath: 'src/config.ts',
110 })}
111 />
112 </div>
113 </blockquote>
114 )
115 }
116 <Content />
117 </Markdown>
118 <License time={article.data.published} lang={article.data.lang} />
119 {backLinks.length > 0 && <BackLinks backLinks={backLinks} />}
120</PostPageLayout>